package github.sf.fw.utils;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public class RetryAndTimeout {
    /**
     * 重试运行
     * 暂不支持多线程
     */
    public void retryExecute(Runnable process, int retryCount) {
        AtomicInteger retry = new AtomicInteger(retryCount);
        AtomicBoolean makeMistakes = new AtomicBoolean(false);
        Exception error = null;
        do {
            try {
                process.run();
                if (makeMistakes.get()) {
                    makeMistakes.set(false);
                }
            } catch (Exception e) {
                makeMistakes.set(true);
                error = e;
            }
        } while (retry.decrementAndGet() > 0 && makeMistakes.get());
        if (retry.get() == 0 && makeMistakes.get()) {
            throw new RuntimeException(error);
        }
    }

    public void runTimeout(Runnable coreFunc, long timeout, TimeUnit timeUnit) {
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        long startTime = System.currentTimeMillis();
        long currentTime = System.currentTimeMillis();
        Future<?> taskFuture = executorService.submit(coreFunc);
        while (!(taskFuture.isDone() || taskFuture.isCancelled())
                && (currentTime - startTime) < timeUnit.toMillis(timeout)) {
            threadSleep(100, TimeUnit.MILLISECONDS);
            currentTime = System.currentTimeMillis();
        }
        if (currentTime - startTime >= timeUnit.toMillis(timeout)) {
            taskFuture.cancel(true);
            executorService.shutdownNow();
            throw new RuntimeException("超时了");
        }
    }

    public void threadSleep(long time, TimeUnit timeUnit) {
        try {
            Thread.sleep(timeUnit.toMillis(time));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
